package com.wanfajie.smsdistribute.common.adapter

import android.support.v7.widget.RecyclerView
import android.util.SparseArray
import android.view.View
import java.util.*

open class RecyclerViewHolder(val view: View) : RecyclerView.ViewHolder(view) {
    private val cache = SparseArray<View>()
    var tag: Any? = null

    fun <T: View> get(id : Int) : T {
        if (cache.indexOfKey(id) >= 0) {
            return cache.get(id) as T
        }

        val v : T = view.findViewById(id)
        cache.put(id, v)
        return v
    }
}

class RecyclerAdapterLinkedList<E, VH: RecyclerViewHolder> private constructor(
        private val rvAdapter: RecyclerView.Adapter<VH>,
        private val mItems: LinkedList<E>
): MutableList<E> by mItems {

    constructor(adapter: RecyclerView.Adapter<VH>, items: Collection<E>): this(adapter, LinkedList(items))

    companion object {

        private class RecyclerItemIterator<E, VH: RecyclerViewHolder>(
                private val iterator: MutableIterator<E>,
                private val rvAdapter: RecyclerView.Adapter<VH>,
                private val needNotify: Boolean = true
        ): MutableIterator<E> by iterator {
            private var index = -1

            override fun next(): E {
                index++
                return iterator.next()
            }

            override fun remove() {
                iterator.remove()
                if (needNotify) rvAdapter.notifyItemRemoved(index)
                index--
            }
        }

        private class RecyclerItemListIterator<T, VH: RecyclerViewHolder>(
                private val listIterator: MutableListIterator<T>,
                private val rvAdapter: RecyclerView.Adapter<VH>,
                private val needNotify: Boolean = true
        ): MutableListIterator<T> by listIterator {

            override fun add(element: T) {
                listIterator.add(element)
                if (needNotify) rvAdapter.notifyItemInserted(nextIndex())
            }

            override fun remove() {
                val index = previousIndex()
                listIterator.remove()
                if (needNotify) rvAdapter.notifyItemRemoved(index)
            }

            override fun set(element: T) {
                val index = previousIndex()
                listIterator.set(element)
                if (needNotify) rvAdapter.notifyItemChanged(index)
            }
        }
    }

    private var mNeedNotify = true

    override fun add(element: E): Boolean {
        val tail = size
        val r = mItems.add(element)
        if (mNeedNotify) rvAdapter.notifyItemInserted(tail)
        return r
    }

    override fun add(index: Int, element: E) {
        mItems.add(index, element)
        if (mNeedNotify) rvAdapter.notifyItemInserted(index)
    }

    override fun addAll(index: Int, elements: Collection<E>): Boolean {
        val r = mItems.addAll(index, elements)
        if (r && mNeedNotify) rvAdapter.notifyItemRangeInserted(index, elements.size)
        return r
    }

    override fun addAll(elements: Collection<E>): Boolean {
        val tail = size
        val r = mItems.addAll(elements)
        if (r && mNeedNotify) rvAdapter.notifyItemRangeInserted(tail, elements.size)
        return r
    }

    override fun clear() {
        val s = size
        mItems.clear()

        if (s != 0 && mNeedNotify)
            rvAdapter.notifyDataSetChanged()
    }

    override fun remove(element: E): Boolean {
        val index = mItems.indexOf(element)
        val r = mItems.remove(element)
        if (r && mNeedNotify) rvAdapter.notifyItemRemoved(index)
        return r
    }

    override fun removeAll(elements: Collection<E>): Boolean {
        val r = mItems.removeAll(elements)
        if (r && mNeedNotify) rvAdapter.notifyDataSetChanged()
        return r
    }

    override fun removeAt(index: Int): E {
        val r = mItems.removeAt(index)
        if (mNeedNotify) rvAdapter.notifyItemRemoved(index)
        return r
    }

    override fun retainAll(elements: Collection<E>): Boolean {
        val r = mItems.retainAll(elements)
        if (r && mNeedNotify) rvAdapter.notifyDataSetChanged()
        return r
    }

    override fun set(index: Int, element: E): E {
        val r = mItems.set(index, element)
        if (mNeedNotify) rvAdapter.notifyItemChanged(index)
        return r
    }

    override fun iterator(): MutableIterator<E> {
        return RecyclerItemIterator(mItems.iterator(), rvAdapter, mNeedNotify)
    }

    override fun listIterator(): MutableListIterator<E> {
        return RecyclerItemListIterator(mItems.listIterator(), rvAdapter, mNeedNotify)
    }

    override fun listIterator(index: Int): MutableListIterator<E> {
        return RecyclerItemListIterator(mItems.listIterator(index), rvAdapter, mNeedNotify)
    }

    infix fun <R> silent(block: RecyclerAdapterLinkedList<E, VH>.() -> R): R {
        mNeedNotify = false
        try {
            return with(this, block)
        } catch (e: Exception) {
            throw e
        } finally {
            mNeedNotify = true
        }
    }
}
